//------------------------------------------------------------------------------
//  binarywriter.cc
//  (C) 2006 Radon Labs GmbH
//------------------------------------------------------------------------------
#include "pch.h"
#include "binarywriter.h"

namespace GBase
{

	//using namespace Util;
	//using namespace System;
	//using namespace Math;

	//------------------------------------------------------------------------------
	/**
	*/
	BinaryWriter::BinaryWriter() :
		enableMapping(false),
		isMapped(false),
		mapCursor(0),
		mapEnd(0)
	{
		// empty
	}

	//------------------------------------------------------------------------------
	/**
	*/
	BinaryWriter::~BinaryWriter()
	{
		if (this->IsOpen())
		{
			this->Close();
		}
	}

	//------------------------------------------------------------------------------
	/**
	*/
	bool
	BinaryWriter::Open()
	{
		if (StreamWriter::Open())
		{
			if (this->enableMapping && this->stream->CanBeMapped())
			{
				this->isMapped = true;
				this->mapCursor = (unsigned char*) this->stream->Map();
				this->mapEnd = this->mapCursor + this->stream->GetSize();
			}
			else
			{
				this->isMapped = false;
				this->mapCursor = 0;
				this->mapEnd = 0;
			}
			return true;
		}
		return false;
	}

	//------------------------------------------------------------------------------
	/**
	*/
	void
	BinaryWriter::Close()
	{
		StreamWriter::Close();
		this->isMapped = false;
		this->mapCursor = 0;
		this->mapEnd = 0;
	}

	//------------------------------------------------------------------------------
	/**
	*/
	void
	BinaryWriter::WriteChar(char c)
	{
		if (this->isMapped)
		{
			checkSlow(this->mapCursor < this->mapEnd);
			*this->mapCursor++ = c;
		}
		else
		{
			this->stream->Write(&c, sizeof(c));
		}
	}

	//------------------------------------------------------------------------------
	/**
	*/
	void
	BinaryWriter::WriteUChar(unsigned char c)
	{
		if (this->isMapped)
		{
			checkSlow(this->mapCursor < this->mapEnd);
			*this->mapCursor++ = c;
		}
		else
		{
			this->stream->Write(&c, sizeof(c));
		}
	}

	//------------------------------------------------------------------------------
	/**
	*/
	void
	BinaryWriter::WriteShort(short s)
	{
		//this->byteOrder.Convert<short>(s);
		if (this->isMapped)
		{
			// note: the memory copy is necessary to circumvent alignment problem on some CPUs
			checkSlow((this->mapCursor + sizeof(s)) <= this->mapEnd);
			//Memory::Copy(&s, this->mapCursor, sizeof(s));
			memcpy(this->mapCursor, &s, sizeof(s));
			this->mapCursor += sizeof(s);
		}
		else
		{
			this->stream->Write(&s, sizeof(s));
		}
	}

	//------------------------------------------------------------------------------
	/**
	*/
	void
	BinaryWriter::WriteUShort(unsigned short s)
	{
		//this->byteOrder.Convert<unsigned short>(s);
		if (this->isMapped)
		{
			// note: the memory copy is necessary to circumvent alignment problem on some CPUs
			checkSlow((this->mapCursor + sizeof(s)) <= this->mapEnd);
			//Memory::Copy(&s, this->mapCursor, sizeof(s));
			memcpy(this->mapCursor, &s, sizeof(s));
			this->mapCursor += sizeof(s);
		}
		else
		{
			this->stream->Write(&s, sizeof(s));
		}
	}

	//------------------------------------------------------------------------------
	/**
	*/
	void
	BinaryWriter::WriteInt(int i)
	{
		//this->byteOrder.Convert<int>(i);
		if (this->isMapped)
		{
			// note: the memory copy is necessary to circumvent alignment problem on some CPUs
			checkSlow((this->mapCursor + sizeof(i)) <= this->mapEnd);
			//Memory::Copy(&i, this->mapCursor, sizeof(i));
			memcpy(this->mapCursor, &i, sizeof(i));
			this->mapCursor += sizeof(i);
		}
		else
		{
			this->stream->Write(&i, sizeof(i));
		}
	}

	//------------------------------------------------------------------------------
	/**
	*/
	void
	BinaryWriter::WriteUInt(unsigned int i)
	{
		//this->byteOrder.Convert<unsigned int>(i);
		if (this->isMapped)
		{
			// note: the memory copy is necessary to circumvent alignment problem on some CPUs
			checkSlow((this->mapCursor + sizeof(i)) <= this->mapEnd);
			//Memory::Copy(&i, this->mapCursor, sizeof(i));
			memcpy(this->mapCursor, &i, sizeof(i));
			this->mapCursor += sizeof(i);
		}
		else
		{
			this->stream->Write(&i, sizeof(i));
		}
	}

	//------------------------------------------------------------------------------
	/**
	*/
	void
	BinaryWriter::WriteFloat(float f)
	{
		//this->byteOrder.Convert<float>(f);
		if (this->isMapped)
		{
			// note: the memory copy is necessary to circumvent alignment problem on some CPUs
			checkSlow((this->mapCursor + sizeof(f)) <= this->mapEnd);
			//Memory::Copy(&f, this->mapCursor, sizeof(f));
			memcpy(this->mapCursor, &f, sizeof(f));
			this->mapCursor += sizeof(f);
		}
		else
		{
			this->stream->Write(&f, sizeof(f));
		}
	}

	//------------------------------------------------------------------------------
	/**
	*/
	void
	BinaryWriter::WriteDouble(double d)
	{
		//this->byteOrder.Convert<double>(d);
		if (this->isMapped)
		{
			// note: the memory copy is necessary to circumvent alignment problem on some CPUs
			checkSlow((this->mapCursor + sizeof(d)) <= this->mapEnd);
			//Memory::Copy(&d, this->mapCursor, sizeof(d));
			memcpy(this->mapCursor, &d, sizeof(d));
			this->mapCursor += sizeof(d);
		}
		else
		{
			this->stream->Write(&d, sizeof(d));
		}
	}

	//------------------------------------------------------------------------------
	/**
	*/
	void
	BinaryWriter::WriteBool(bool b)
	{
		if (this->isMapped)
		{
			// note: the memory copy is necessary to circumvent alignment problem on some CPUs
			checkSlow((this->mapCursor + sizeof(b)) <= this->mapEnd);
			//Memory::Copy(&b, this->mapCursor, sizeof(b));
			memcpy(this->mapCursor, &b, sizeof(b));
			this->mapCursor += sizeof(b);
		}
		else
		{
			this->stream->Write(&b, sizeof(b));
		}
	}

	//------------------------------------------------------------------------------
	/**
	*/
	void
	BinaryWriter::WriteLLong(long long l)
	{
		if (this->isMapped)
		{
			// note: the memory copy is necessary to circumvent alignment problem on some CPUs
			checkSlow((this->mapCursor + sizeof(l)) <= this->mapEnd);
			//Memory::Copy(&b, this->mapCursor, sizeof(b));
			memcpy(this->mapCursor, &l, sizeof(l));
			this->mapCursor += sizeof(l);
		}
		else
		{
			this->stream->Write(&l, sizeof(l));
		}
	}

	//------------------------------------------------------------------------------
	/**
	*/
	void
	BinaryWriter::WriteULLong(unsigned long long l)
	{
		if (this->isMapped)
		{
			// note: the memory copy is necessary to circumvent alignment problem on some CPUs
			checkSlow((this->mapCursor + sizeof(l)) <= this->mapEnd);
			//Memory::Copy(&b, this->mapCursor, sizeof(b));
			memcpy(this->mapCursor, &l, sizeof(l));
			this->mapCursor += sizeof(l);
		}
		else
		{
			this->stream->Write(&l, sizeof(l));
		}
	}

	void BinaryWriter::WriteString1024(const char* txt)
	{
		if (txt == 0 || txt[0] == 0)
			this->WriteUShort(0);
		unsigned int txt_len = strlen(txt);
		checkSlow(txt_len < (1<<10));
		if (txt_len > 1023)
		{
			txt_len = 1023;
		}

		this->WriteUShort(unsigned short(txt_len));

		if (txt_len == 0)
			return;

		if (this->isMapped)
		{
			checkSlow((this->mapCursor + txt_len) <= this->mapEnd);
			//Memory::Copy(s.AsCharPtr(), this->mapCursor, s.Length());
			memcpy(this->mapCursor, txt, txt_len);
			this->mapCursor += txt_len;
		}
		else
		{
			this->stream->Write((void*)txt, txt_len);
		}

	}
	
	void
	BinaryWriter::WriteRawData(const void* ptr, unsigned int numBytes)
	{
		checkSlow((ptr != 0) && (numBytes > 0));
		if (this->isMapped)
		{
			checkSlow((this->mapCursor + numBytes) <= this->mapEnd);
			//Memory::Copy(ptr, this->mapCursor, numBytes);
			memcpy(this->mapCursor, ptr, numBytes);
			this->mapCursor += numBytes;
		}
		else
		{
			this->stream->Write(ptr, numBytes);
		}
	}

} // namespace Core
